#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
SMTP邮件发送工具
支持SSL/TLS加密，授权码登录，自定义发送内容和发送者
"""

import tkinter as tk
from tkinter import ttk, messagebox, scrolledtext
import smtplib
import ssl
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart
from email.mime.base import MIMEBase
from email import encoders
import json
import os
import threading
from datetime import datetime


class EmailSender:
    def __init__(self, root):
        self.root = root
        self.root.title("SMTP邮件发送工具")
        self.root.geometry("800x700")
        self.root.resizable(True, True)
        
        # 配置文件路径
        self.config_file = "email_config.json"
        
        # 创建界面
        self.create_widgets()
        
        # 加载配置
        self.load_config()
        
    def create_widgets(self):
        """创建GUI界面"""
        # 创建主框架
        main_frame = ttk.Frame(self.root, padding="10")
        main_frame.grid(row=0, column=0, sticky=(tk.W, tk.E, tk.N, tk.S))
        
        # 配置网格权重
        self.root.columnconfigure(0, weight=1)
        self.root.rowconfigure(0, weight=1)
        main_frame.columnconfigure(1, weight=1)
        
        # SMTP服务器配置区域
        config_frame = ttk.LabelFrame(main_frame, text="SMTP服务器配置", padding="10")
        config_frame.grid(row=0, column=0, columnspan=2, sticky=(tk.W, tk.E), pady=(0, 10))
        config_frame.columnconfigure(1, weight=1)
        
        # SMTP服务器
        ttk.Label(config_frame, text="SMTP服务器:").grid(row=0, column=0, sticky=tk.W, pady=2)
        self.smtp_server_var = tk.StringVar()
        smtp_combo = ttk.Combobox(config_frame, textvariable=self.smtp_server_var, width=30)
        smtp_combo['values'] = (
            'smtp.qq.com:587',
            'smtp.163.com:25',
            'smtp.126.com:25',
            'smtp.gmail.com:587',
            'smtp.outlook.com:587',
            'smtp.sina.com:25'
        )
        smtp_combo.grid(row=0, column=1, sticky=(tk.W, tk.E), pady=2, padx=(5, 0))
        
        # 端口
        ttk.Label(config_frame, text="端口:").grid(row=1, column=0, sticky=tk.W, pady=2)
        self.port_var = tk.StringVar(value="587")
        ttk.Entry(config_frame, textvariable=self.port_var, width=10).grid(row=1, column=1, sticky=tk.W, pady=2, padx=(5, 0))
        
        # SSL/TLS选项
        self.use_ssl_var = tk.BooleanVar(value=True)
        ttk.Checkbutton(config_frame, text="使用SSL/TLS加密", variable=self.use_ssl_var).grid(row=2, column=0, columnspan=2, sticky=tk.W, pady=2)
        
        # 登录用户
        ttk.Label(config_frame, text="登录邮箱:").grid(row=3, column=0, sticky=tk.W, pady=2)
        self.username_var = tk.StringVar()
        ttk.Entry(config_frame, textvariable=self.username_var, width=40).grid(row=3, column=1, sticky=(tk.W, tk.E), pady=2, padx=(5, 0))
        
        # 授权码
        ttk.Label(config_frame, text="授权码:").grid(row=4, column=0, sticky=tk.W, pady=2)
        self.password_var = tk.StringVar()
        password_entry = ttk.Entry(config_frame, textvariable=self.password_var, show="*", width=40)
        password_entry.grid(row=4, column=1, sticky=(tk.W, tk.E), pady=2, padx=(5, 0))
        
        # 显示/隐藏密码按钮
        self.show_password_var = tk.BooleanVar()
        ttk.Checkbutton(config_frame, text="显示密码", variable=self.show_password_var, 
                       command=lambda: self.toggle_password_visibility(password_entry)).grid(row=5, column=0, columnspan=2, sticky=tk.W, pady=2)
        
        # 邮件内容区域
        content_frame = ttk.LabelFrame(main_frame, text="邮件内容", padding="10")
        content_frame.grid(row=1, column=0, columnspan=2, sticky=(tk.W, tk.E, tk.N, tk.S), pady=(0, 10))
        content_frame.columnconfigure(1, weight=1)
        content_frame.rowconfigure(4, weight=1)
        main_frame.rowconfigure(1, weight=1)
        
        # 发送者
        ttk.Label(content_frame, text="发送者:").grid(row=0, column=0, sticky=tk.W, pady=2)
        self.sender_var = tk.StringVar()
        ttk.Entry(content_frame, textvariable=self.sender_var, width=40).grid(row=0, column=1, sticky=(tk.W, tk.E), pady=2, padx=(5, 0))
        
        # 收件人
        ttk.Label(content_frame, text="收件人:").grid(row=1, column=0, sticky=tk.W, pady=2)
        self.recipient_var = tk.StringVar()
        ttk.Entry(content_frame, textvariable=self.recipient_var, width=40).grid(row=1, column=1, sticky=(tk.W, tk.E), pady=2, padx=(5, 0))
        
        # 抄送
        ttk.Label(content_frame, text="抄送:").grid(row=2, column=0, sticky=tk.W, pady=2)
        self.cc_var = tk.StringVar()
        ttk.Entry(content_frame, textvariable=self.cc_var, width=40).grid(row=2, column=1, sticky=(tk.W, tk.E), pady=2, padx=(5, 0))
        
        # 主题
        ttk.Label(content_frame, text="主题:").grid(row=3, column=0, sticky=tk.W, pady=2)
        self.subject_var = tk.StringVar()
        ttk.Entry(content_frame, textvariable=self.subject_var, width=40).grid(row=3, column=1, sticky=(tk.W, tk.E), pady=2, padx=(5, 0))
        
        # 邮件内容
        ttk.Label(content_frame, text="邮件内容:").grid(row=4, column=0, sticky=(tk.NW), pady=2)
        self.content_text = scrolledtext.ScrolledText(content_frame, height=10, width=50)
        self.content_text.grid(row=4, column=1, sticky=(tk.W, tk.E, tk.N, tk.S), pady=2, padx=(5, 0))
        
        # 按钮区域
        button_frame = ttk.Frame(main_frame)
        button_frame.grid(row=2, column=0, columnspan=2, pady=10)
        
        # 测试连接按钮
        ttk.Button(button_frame, text="测试连接", command=self.test_connection).pack(side=tk.LEFT, padx=(0, 5))
        
        # 保存配置按钮
        ttk.Button(button_frame, text="保存配置", command=self.save_config).pack(side=tk.LEFT, padx=(0, 5))
        
        # 发送邮件按钮
        ttk.Button(button_frame, text="发送邮件", command=self.send_email).pack(side=tk.LEFT, padx=(0, 5))
        
        # 清空内容按钮
        ttk.Button(button_frame, text="清空内容", command=self.clear_content).pack(side=tk.LEFT, padx=(0, 5))
        
        # 状态栏
        self.status_var = tk.StringVar(value="就绪")
        status_bar = ttk.Label(main_frame, textvariable=self.status_var, relief=tk.SUNKEN, anchor=tk.W)
        status_bar.grid(row=3, column=0, columnspan=2, sticky=(tk.W, tk.E), pady=(10, 0))
        
    def toggle_password_visibility(self, password_entry):
        """切换密码显示/隐藏"""
        if self.show_password_var.get():
            password_entry.config(show="")
        else:
            password_entry.config(show="*")
    
    def update_status(self, message):
        """更新状态栏"""
        self.status_var.set(f"{datetime.now().strftime('%H:%M:%S')} - {message}")
        self.root.update_idletasks()
    
    def parse_smtp_server(self):
        """解析SMTP服务器地址和端口"""
        server_text = self.smtp_server_var.get()
        if ':' in server_text:
            server, port = server_text.split(':')
            self.port_var.set(port)
            return server
        return server_text
    
    def test_connection(self):
        """测试SMTP连接"""
        def test_thread():
            try:
                self.update_status("正在测试连接...")
                
                # 获取服务器信息
                smtp_server = self.parse_smtp_server()
                port = int(self.port_var.get())
                username = self.username_var.get()
                password = self.password_var.get()
                
                if not all([smtp_server, username, password]):
                    messagebox.showerror("错误", "请填写完整的SMTP服务器信息")
                    return
                
                # 创建SSL上下文
                context = ssl.create_default_context()
                
                # 连接服务器
                if self.use_ssl_var.get():
                    server = smtplib.SMTP_SSL(smtp_server, port, context=context)
                else:
                    server = smtplib.SMTP(smtp_server, port)
                    if port == 587:  # STARTTLS
                        server.starttls(context=context)
                
                # 登录
                server.login(username, password)
                server.quit()
                
                self.update_status("连接测试成功！")
                messagebox.showinfo("成功", "SMTP连接测试成功！")
                
            except Exception as e:
                self.update_status(f"连接测试失败: {str(e)}")
                messagebox.showerror("连接失败", f"SMTP连接测试失败:\n{str(e)}")
        
        # 在新线程中执行测试
        threading.Thread(target=test_thread, daemon=True).start()
    
    def send_email(self):
        """发送邮件"""
        def send_thread():
            try:
                self.update_status("正在发送邮件...")
                
                # 获取邮件信息
                smtp_server = self.parse_smtp_server()
                port = int(self.port_var.get())
                username = self.username_var.get()
                password = self.password_var.get()
                sender = self.sender_var.get() or username
                recipient = self.recipient_var.get()
                cc = self.cc_var.get()
                subject = self.subject_var.get()
                content = self.content_text.get("1.0", tk.END).strip()
                
                # 验证必填字段
                if not all([smtp_server, username, password, recipient, subject, content]):
                    messagebox.showerror("错误", "请填写完整的邮件信息")
                    return
                
                # 创建邮件
                msg = MIMEMultipart()
                msg['From'] = sender
                msg['To'] = recipient
                if cc:
                    msg['Cc'] = cc
                msg['Subject'] = subject
                
                # 添加邮件内容
                msg.attach(MIMEText(content, 'plain', 'utf-8'))
                
                # 创建SSL上下文
                context = ssl.create_default_context()
                
                # 连接服务器并发送
                if self.use_ssl_var.get():
                    server = smtplib.SMTP_SSL(smtp_server, port, context=context)
                else:
                    server = smtplib.SMTP(smtp_server, port)
                    if port == 587:  # STARTTLS
                        server.starttls(context=context)
                
                # 登录
                server.login(username, password)
                
                # 发送邮件
                recipients = [recipient]
                if cc:
                    recipients.extend([email.strip() for email in cc.split(',')])
                
                server.send_message(msg)
                server.quit()
                
                self.update_status("邮件发送成功！")
                messagebox.showinfo("成功", "邮件发送成功！")
                
            except Exception as e:
                self.update_status(f"邮件发送失败: {str(e)}")
                messagebox.showerror("发送失败", f"邮件发送失败:\n{str(e)}")
        
        # 在新线程中执行发送
        threading.Thread(target=send_thread, daemon=True).start()
    
    def save_config(self):
        """保存配置到文件"""
        try:
            config = {
                'smtp_server': self.smtp_server_var.get(),
                'port': self.port_var.get(),
                'use_ssl': self.use_ssl_var.get(),
                'username': self.username_var.get(),
                'sender': self.sender_var.get()
            }
            
            with open(self.config_file, 'w', encoding='utf-8') as f:
                json.dump(config, f, ensure_ascii=False, indent=2)
            
            self.update_status("配置已保存")
            messagebox.showinfo("成功", "配置已保存到文件")
            
        except Exception as e:
            messagebox.showerror("保存失败", f"保存配置失败:\n{str(e)}")
    
    def load_config(self):
        """从文件加载配置"""
        try:
            if os.path.exists(self.config_file):
                with open(self.config_file, 'r', encoding='utf-8') as f:
                    config = json.load(f)
                
                self.smtp_server_var.set(config.get('smtp_server', ''))
                self.port_var.set(config.get('port', '587'))
                self.use_ssl_var.set(config.get('use_ssl', True))
                self.username_var.set(config.get('username', ''))
                self.sender_var.set(config.get('sender', ''))
                
                self.update_status("配置已加载")
                
        except Exception as e:
            print(f"加载配置失败: {e}")
    
    def clear_content(self):
        """清空邮件内容"""
        self.recipient_var.set('')
        self.cc_var.set('')
        self.subject_var.set('')
        self.content_text.delete("1.0", tk.END)
        self.update_status("内容已清空")


def main():
    """主函数"""
    root = tk.Tk()
    app = EmailSender(root)
    
    # 设置窗口图标（如果有的话）
    try:
        root.iconbitmap("icon.ico")
    except:
        pass
    
    # 居中显示窗口
    root.update_idletasks()
    x = (root.winfo_screenwidth() // 2) - (root.winfo_width() // 2)
    y = (root.winfo_screenheight() // 2) - (root.winfo_height() // 2)
    root.geometry(f"+{x}+{y}")
    
    root.mainloop()


if __name__ == "__main__":
    main()
